import WebGl from '@/modules/three';
// import fontJson from 'three/examples/fonts/helvetiker_regular.typeface.json'
const fontJson = require('three/examples/fonts/helvetiker_regular.typeface.json');

const { Three, TWEEN, dat, Stats, OrbitControls } = WebGl;

class WebGlControl {
  private container: any;
  private camera: any;
  private scene: any;
  private renderer: any;
  private stats: any;
  private animateFrame: any;
  private tween: any;
  private controls: any;
  private clock: any = new Three.Clock();

  private Geometrys: {
    cubeGeo?: any;
    lineGeo?: any;
  } = {}; //保存所有Geometry，方便统一销毁
  private Materials: {
    cubeMate?: any;
  } = {}; //保存所有Material，方便统一销毁
  private Meshs: {
    cubes?: any[];
    trunk?: any;
  } = {};
  private cubeGroup: any = {};
  private curve: any;

  private GuiInit: any = null;
  private guiData: any = {
    x: 0.005,
    color: '#000000',
    autoRotate: true,
  };
  private pointList = [
    { x: 10, y: 10, z: -10 },
    { x: 10, y: 0, z: 10 },
    { x: -10, y: 0, z: 10 },
    { x: -10, y: 0, z: -10 },
    { x: 0, y: 10, z: 0 },
  ];

  public init = (id: string) => {
    // if(this.scene) {return}
    this.container = document.getElementById(id);
    let width = this.container.clientWidth,
      height = this.container.clientHeight;

    this.scene = new Three.Scene();

    this.camera = new Three.PerspectiveCamera(60, width / height, 1, 500);
    this.camera.position.x = 0;
    this.camera.position.y = 0;
    this.camera.position.z = 80;
    this.camera.lookAt(this.scene.position);

    this.renderer = new Three.WebGLRenderer();
    // this.renderer.setClearColor( 0xffffff );
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(width, height);
    this.container.appendChild(this.renderer.domElement);

    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.controls.enableDamping = true; //阻尼
    this.controls.dampingFactor = 0.1; //阻尼

    this.cubeGroup = new Three.Group();
    this.scene.add(this.cubeGroup);
    this.addThings();
    this.addLight(); //+光源
    this.animate(); //开始动
    this.initStats();

    this.initGui();
  };
  public destroy = () => {
    this.toggleGui(0);
    Object.values(this.Geometrys).forEach((e) => {
      e.dispose();
    });
    Object.values(this.Materials).forEach((e) => {
      e.dispose();
    });
    this.scene.clear();
    this.renderer.dispose();
    this.renderer.forceContextLoss();
    this.camera = null;
    this.scene = null;
    this.renderer = null;
    this.GuiInit = null;
    this.stats = null;
    if (this.tween) {
      this.tween.stop();
      this.tween = null;
    }
    cancelAnimationFrame(this.animateFrame);
  };

  private initStats = () => {
    this.stats = new Stats();
    this.stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
    this.stats.dom.style.position = 'absolute';
    this.container.appendChild(this.stats.dom);
  };

  public initGui = () => {
    if (this.GuiInit) {
      this.toggleGui();
      return;
    }
    this.GuiInit = new dat.GUI({
      // autoPlace: false
    });

    this.GuiInit.domElement.style.position = 'absolute';
    this.GuiInit.domElement.style.right = '10px';
    this.GuiInit.domElement.style.top = '10px';

    let GuiController = this.GuiInit.addFolder('控制窗口');
    GuiController.add(this.guiData, 'x', -0.1, 0.1, 0.005).name('自转速度');
    GuiController.addColor(this.guiData, 'color').name('背景颜色');
    GuiController.open();

    // let cubeGui = this.GuiInit.addFolder("cube position");
    // cubeGui.open()
  };

  public toggleGui = (state: any = null) => {
    if (!this.GuiInit || !this.GuiInit.domElement) {
      return;
    }
    let display = this.GuiInit.domElement.style.display == 'none' ? '' : 'none';
    if (state == 0) {
      display = 'none';
    }
    this.GuiInit.domElement.style.display = display;
  };

  private addLight = () => {
    let ambi = new Three.AmbientLight(0x686868);
    this.scene.add(ambi);
    let dirLight = new Three.DirectionalLight(0xffffff);
    dirLight.position.set(100, 80, 100);
    dirLight.intensity = 0.6;
    this.scene.add(dirLight);
    // let light = new Three.PointLight( 0xFFFF00 );
    // light.position.set( -100, 100, 0 );
    // this.scene.add(light);
  };

  private addThings = () => {
    // const axesHelper = new Three.AxesHelper( 800 );
    // this.scene.add( axesHelper )  //添加坐标轴；红线是X轴，绿线是Y轴，蓝线是Z轴

    this.addCubes();
    this.addTrunk();
    this.addCurves();

    this.initTween();
  };

  private addTrunk = () => {
    const geometry = new Three.ConeGeometry(2, 8, 4);
    const material = new Three.MeshPhongMaterial({ color: 0xffff00 });
    this.Meshs.trunk = new Three.Mesh(geometry, material);
    // this.Meshs.trunk.rotation.set(0, 0, Math.PI/2)
    this.scene.add(this.Meshs.trunk);
  };
  private addCubes = () => {
    this.Geometrys.cubeGeo = new Three.BoxBufferGeometry(1, 1, 1);
    this.Materials.cubeMate = new Three.MeshBasicMaterial(0xffffff);

    this.pointList.map((pos) => {
      this.addCube(pos);
    });
  };
  private addCube = (pos) => {
    const cube = new Three.Mesh(
      this.Geometrys.cubeGeo,
      this.Materials.cubeMate,
    );
    cube.position.copy(pos);
    // this.Meshs.cubes?.push(cube)
    this.cubeGroup.add(cube);
  };
  private addCurves = () => {
    this.curve = new Three.CatmullRomCurve3(
      // this.pointList.map(e => new Three.Vector3(e.x, e.y, e.z))
      this.cubeGroup.children.map((cube) => cube.position), // 直接绑定方块的position以便后续用方块调整曲线
    );
    this.curve.curveType = 'catmullrom'; // 曲线类型 centripetal、chordal和catmullrom
    this.curve.closed = true; // 曲线是否闭合

    const points = this.curve.getPoints(50); // 50等分获取曲线点数组
    this.Geometrys.lineGeo = new Three.BufferGeometry().setFromPoints(points);
    const line = new Three.LineLoop(
      this.Geometrys.lineGeo,
      new Three.LineBasicMaterial({ color: 0x00ff00 }),
    ); // 绘制实体线条，仅用于示意曲线，后面的向量线条同理，相关代码就省略了

    this.scene.add(line);
  };

  private changePosition = (t) => {
    const position = this.curve.getPointAt(t); // t: 当前点在线条上的位置百分比，后面计算
    this.Meshs.trunk.position.copy(position);

    const target = this.cubeGroup.children[3].position; //第四个点位
    const desired = target.clone().sub(position); // 目标方向向量
    const distance = desired.length(); // 到目标点的距离
    // console.log('target: ', target)
    if (distance < 1) {
      // console.log('this.addpointMark', this.addpointMark)
      if (this.addpointMark) {
        this.addpointMark = false;
        // 到达第四个点位，将第四个点位设为1，并重新生成1、2点位
        this.addPoint();
        // target.copy(this.generateTarget());
        // desired.copy(target).sub(this.position);
      }
    } else {
      this.addpointMark = true;
    }

    //改变物体朝向
    const tangent = this.curve.getTangentAt(t);
    const lookAtVec = tangent.add(position); // 位置向量和切线向量相加即为所需朝向的点向量
    this.Meshs.trunk.lookAt(lookAtVec);
  };

  private timeMax = 10;
  private timeDur = 0;
  private handleMove = () => {
    const delta = this.clock.getDelta();
    // console.log(delta);
    this.timeDur += delta;
    if (this.timeDur > this.timeMax) {
      this.timeDur = 0;
    }
    const t = this.timeDur / this.timeMax;

    this.changePosition(t);
    // this.changePosition(0.9);

    // if(t >= 0.5 && this.addpointMark) {
    //   this.addpointMark = false;
    //   this.addPoint()
    // }
  };
  private addpointMark = true;
  private addPoint = () => {
    const x = Math.random() * 40 - 20;
    const y = Math.random() * 40 - 20;
    const z = Math.random() * 40 - 20;
    const res = { x, y, z };
    const x2 = Math.random() * 40 - 20;
    const y2 = Math.random() * 40 - 20;
    const z2 = Math.random() * 40 - 20;
    const res2 = { x: x2, y: y2, z: z2 };
    this.pointList = [
      this.pointList[3],
      this.pointList[4],
      res,
      res2,
      this.pointList[2],
    ];

    this.cubeGroup.children.map((cube, ind) => {
      const e = this.pointList[ind];
      const pos = new Three.Vector3(e.x, e.y, e.z);
      cube.position.copy(pos);
    });
    this.curve = new Three.CatmullRomCurve3(
      this.pointList.map((e) => new Three.Vector3(e.x, e.y, e.z)),
      // this.cubeGroup.children.map((cube) => cube.position) // 直接绑定方块的position以便后续用方块调整曲线
    );
    this.timeDur = 0;
    const points = this.curve.getPoints(50); // 50等分获取曲线点数组
    this.Geometrys.lineGeo.setFromPoints(points);

    console.log(this.pointList, this.cubeGroup);
  };

  private initTween = () => {
    // var pos: any = { val: 1 };
    // this.tween = new TWEEN.Tween(pos)
    //   .to({ val: 0 }, 1000)
    //   .easing(TWEEN.Easing.Quadratic.InOut)
    //   .delay(200)
    //   .onUpdate(callback);
    // let tweenBack = new TWEEN.Tween(pos)
    //   .to({ val: 1 }, 1000)
    //   .easing(TWEEN.Easing.Quadratic.InOut)
    //   .delay(200)
    //   .onUpdate(callback);
    // this.tween.chain(tweenBack);
    // tweenBack.chain(this.tween);
    // this.tween.start();
    // let that = this;
    // function callback(res) {
    //   that.Materials.starsMaterial.uniforms.val.value = res.val;
    // }
  };

  private animate = () => {
    // if(!this.renderer){return;}
    if (this.stats) {
      this.stats.begin();
    }

    this.render();
    TWEEN.update();
    this.controls.update();

    if (this.stats) {
      this.stats.end();
    }
    this.animateFrame = requestAnimationFrame(this.animate);
  };
  private render = () => {
    this.handleMove();

    this.renderer.setClearColor(this.guiData.color, 1.0);
    // if(this.guiData.autoRotate){
    // }
    this.renderer.render(this.scene, this.camera);
  };
}

const webGlControl = new WebGlControl();
export default webGlControl;
